import streamlit as st
import os
import time
import cv2
import database as db
from detector import PersonDetector
from tracker import PersonTracker
import numpy as np
import threading
from datetime import datetime

# 存储处理状态
if 'processing_videos' not in st.session_state:
    st.session_state.processing_videos = {}

def render():
    """渲染检测与跟踪界面"""
    # 检查处理状态
    check_process_status()
    
    st.title("行人检测与轨迹跟踪")
    
    # 检查是否选择了视频
    if 'selected_video_id' not in st.session_state or 'selected_video_path' not in st.session_state:
        st.warning("请先从文件上传页面选择一个视频")
        if st.button("返回上传页面"):
            st.session_state.current_page = "upload"
            st.rerun()
        return
    
    # 获取视频信息
    video_id = st.session_state.selected_video_id
    video_path = st.session_state.selected_video_path
    
    # 显示视频信息
    video_info = get_video_info(video_path)
    st.subheader("视频信息")
    
    col1, col2 = st.columns(2)
    with col1:
        st.write(f"**文件名**: {os.path.basename(video_path)}")
        st.write(f"**分辨率**: {video_info['width']} x {video_info['height']}")
    
    with col2:
        st.write(f"**时长**: {video_info['duration']:.2f} 秒")
        st.write(f"**帧率**: {video_info['fps']:.2f} FPS")
    
    # 检查视频是否已处理
    video_details = db.get_videos(user_id=None)
    video_details = [v for v in video_details if v['id'] == video_id]
    
    if video_details and video_details[0]['processed']:
        # 视频已处理，显示处理结果
        processed_video_path = video_details[0]['processed_path']
        st.subheader("处理结果")
        
        # 显示视频播放器
        try:
            # 检查处理后的视频是否存在
            if not os.path.exists(processed_video_path):
                st.error(f"处理后的视频文件不存在: {processed_video_path}")
            else:
                # 确保视频文件大小合适
                file_size_mb = os.path.getsize(processed_video_path) / (1024 * 1024)
                st.write(f"处理后视频大小: {file_size_mb:.2f} MB")
                
                # 使用Streamlit视频组件播放视频
                if serve_video(processed_video_path):
                    st.success("视频处理完成，已成功加载！")
                else:
                    st.error("视频播放失败，请联系管理员获取帮助")
        except Exception as e:
            st.error(f"显示视频时出错: {str(e)}")
                
        # 显示视频文件路径信息（用于调试）
        with st.expander("显示视频路径信息（用于调试）"):
            st.write(f"原始视频路径: {video_path}")
            st.write(f"处理后视频路径: {processed_video_path}")
            if 'static_path' in locals():
                st.write(f"静态资源路径: {static_path}")
            
            # 检查文件访问权限
            if os.path.exists(processed_video_path):
                st.write(f"文件存在: ✓")
                st.write(f"文件大小: {os.path.getsize(processed_video_path) / (1024*1024):.2f} MB")
                st.write(f"可读权限: {'✓' if os.access(processed_video_path, os.R_OK) else '✗'}")
            else:
                st.write(f"文件存在: ✗")
        
        # 添加查看轨迹分析按钮
        if st.button("查看轨迹分析"):
            st.session_state.current_page = "visualization"
            st.rerun()
    else:
        # 视频未处理，显示处理选项
        st.subheader("处理选项")
        
        with st.form("processing_form"):
            conf_threshold = st.slider("置信度阈值", min_value=0.1, max_value=1.0, value=0.5, step=0.05)
            st.write("---")
            col1, col2 = st.columns(2)
            with col1:
                process_button = st.form_submit_button("开始处理")
            with col2:
                cancel_button = st.form_submit_button("取消")
            
            if process_button:
                # 开始处理视频
                start_processing(video_id, video_path, conf_threshold)
            
            if cancel_button:
                st.session_state.current_page = "upload"
                st.rerun()
        
        # 如果正在处理，显示进度
        if video_id in st.session_state.processing_videos:
            progress = st.session_state.processing_videos[video_id]
            
            if progress['status'] == 'processing':
                st.info(f"正在处理视频... ({progress['progress']:.1f}%)")
                progress_bar = st.progress(float(progress['progress']) / 100)
                
                # 自动刷新页面以更新进度
                if progress['progress'] < 100:
                    time.sleep(1)
                    st.rerun()
                else:
                    # 处理完成，更新UI但不立即刷新
                    # 检查视频是否已处理完成并存在于数据库中
                    updated_video_details = db.get_videos(user_id=None)
                    updated_video_details = [v for v in updated_video_details if v['id'] == video_id]
                    
                    if updated_video_details and updated_video_details[0]['processed']:
                        st.success("视频处理完成！请点击下方按钮查看结果")
                        if st.button("查看处理结果"):
                            # 清除处理状态
                            if video_id in st.session_state.processing_videos:
                                st.session_state.processing_videos.pop(video_id)
                            st.rerun()
                    else:
                        # 如果还没有检测到数据库更新，等待一段时间
                        st.success("视频处理已完成，正在准备结果...")
                        time.sleep(2)
                        st.rerun()
            
            elif progress['status'] == 'completed':
                # 显示完成状态
                st.success("视频处理完成！请点击下方按钮查看结果")
                progress_bar = st.progress(1.0)  # 显示满进度条
                
                if st.button("查看处理结果"):
                    # 清除处理状态
                    if video_id in st.session_state.processing_videos:
                        st.session_state.processing_videos.pop(video_id)
                    st.rerun()
            
            elif progress['status'] == 'error':
                st.error(f"处理出错: {progress['message']}")

def get_video_info(video_path):
    """获取视频信息"""
    cap = cv2.VideoCapture(video_path)
    
    if not cap.isOpened():
        return {
            'width': 0,
            'height': 0,
            'fps': 0,
            'frame_count': 0,
            'duration': 0
        }
    
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fps = cap.get(cv2.CAP_PROP_FPS)
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    duration = frame_count / fps if fps > 0 else 0
    
    cap.release()
    
    return {
        'width': width,
        'height': height,
        'fps': fps,
        'frame_count': frame_count,
        'duration': duration
    }

def start_processing(video_id, video_path, conf_threshold):
    """开始处理视频"""
    # 初始化进度信息
    st.session_state.processing_videos[video_id] = {
        'status': 'processing',
        'progress': 0,
        'message': ''
    }
    
    # 清除可能存在的旧进度文件
    for file_path in ["data/temp_progress.txt", "data/temp_progress_value.txt", "data/temp_error.txt"]:
        if os.path.exists(file_path):
            try:
                os.remove(file_path)
                print(f"已清除旧的状态文件: {file_path}")
            except Exception as e:
                print(f"清除文件 {file_path} 时出错: {e}")
    
    # 创建输出目录
    os.makedirs("data/processed", exist_ok=True)
    
    # 生成输出文件路径
    output_filename = f"processed_{video_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
    output_path = os.path.join("data/processed", output_filename)
    
    # 在后台线程中处理视频
    process_args = (video_id, video_path, output_path, conf_threshold)
    
    # 使用线程处理，但不直接访问session_state
    thread = threading.Thread(
        target=process_video_safe,
        args=process_args
    )
    thread.daemon = True
    thread.start()

def process_video_safe(*args):
    """安全的视频处理包装函数，避免线程中直接访问session_state"""
    try:
        video_id, video_path, output_path, conf_threshold = args
        
        # 获取视频信息
        cap = cv2.VideoCapture(video_path)
        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        fps = cap.get(cv2.CAP_PROP_FPS)
        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        duration = total_frames / fps if fps > 0 else 0
        cap.release()
        
        # 定义进度更新回调函数
        def update_progress_safe(progress_ratio):
            progress_percent = progress_ratio * 100
            # 通过写入临时文件更新进度
            with open("data/temp_progress_value.txt", "w") as f:
                f.write(f"{video_id}:{progress_percent}")
        
        # 初始化检测器和跟踪器
        detector = PersonDetector(conf_thres=conf_threshold)
        tracker = PersonTracker(detector)
        
        # 处理视频
        try:
            # 跟踪视频，传入进度回调函数
            tracks = tracker.track_video(video_path, output_path, progress_callback=update_progress_safe)
            
            # 检查视频是否已修复或重新编码（如果ensure_playable_video返回了不同的路径）
            actual_output_path = output_path
            if os.path.exists(output_path):
                base_dir = os.path.dirname(output_path)
                filename = os.path.basename(output_path)
                name, ext = os.path.splitext(filename)
                fixed_path = os.path.join(base_dir, f"{name}_fixed{ext}")
                
                # 如果存在修复后的视频，使用它
                if os.path.exists(fixed_path) and os.path.getsize(fixed_path) > 0:
                    actual_output_path = fixed_path
                    print(f"使用修复后的视频路径: {actual_output_path}")
            
            # 确保视频格式适合Web播放（尝试使用FFmpeg进行转换）
            web_compatible_path = os.path.join(base_dir, f"{name}_h264{ext}")
            try:
                print(f"将视频转换为高质量H.264格式...")
                import subprocess
                
                # 使用FFmpeg将视频转换为高质量H.264格式，优化Streamlit播放
                cmd = [
                    'ffmpeg', '-y', '-i', actual_output_path, 
                    '-c:v', 'libx264',                  # H.264编码器
                    '-preset', 'slow',                  # 慢速预设，提高质量
                    '-profile:v', 'high',               # 高级编码配置文件
                    '-level', '4.1',                    # 兼容级别，适合大多数设备
                    '-crf', '18',                       # 恒定质量因子（18-28是好的值，越低质量越高）
                    '-pix_fmt', 'yuv420p',              # 确保兼容大多数播放器
                    '-movflags', '+faststart',          # 优化Web播放
                    '-bf', '2',                         # B帧设置
                    '-g', '30',                         # GOP大小
                    '-keyint_min', '15',                # 最小关键帧间隔
                    '-sc_threshold', '40',              # 场景变化阈值
                    '-an',                              # 去除音频（如果不需要）
                    web_compatible_path
                ]
                
                print(f"执行FFmpeg命令: {' '.join(cmd)}")
                
                # 尝试执行FFmpeg命令
                process = subprocess.Popen(
                    cmd, 
                    stdout=subprocess.PIPE, 
                    stderr=subprocess.PIPE
                )
                stdout, stderr = process.communicate()
                
                # 检查转换结果
                if process.returncode == 0 and os.path.exists(web_compatible_path) and os.path.getsize(web_compatible_path) > 0:
                    print(f"成功转换为高质量H.264格式: {web_compatible_path}")
                    print(f"转换后视频大小: {os.path.getsize(web_compatible_path) / (1024*1024):.2f} MB")
                    actual_output_path = web_compatible_path
                else:
                    print(f"高质量转换失败，返回代码: {process.returncode}")
                    print(f"错误信息: {stderr.decode('utf-8', errors='ignore')}")
                    
                    # 使用更简单的H.264转换命令
                    print("尝试使用简化的H.264转换命令...")
                    simple_cmd = [
                        'ffmpeg', '-y', '-i', actual_output_path,
                        '-c:v', 'libx264',               # H.264编码器
                        '-preset', 'medium',             # 平衡速度和质量
                        '-profile:v', 'baseline',        # 基础配置，最大兼容性
                        '-level', '3.0',                 # 兼容级别
                        '-crf', '23',                    # 中等质量
                        '-pix_fmt', 'yuv420p',           # 确保兼容大多数播放器
                        '-movflags', '+faststart',       # 优化Web播放
                        '-an',                           # 去除音频
                        web_compatible_path
                    ]
                    
                    process = subprocess.Popen(
                        simple_cmd,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE
                    )
                    stdout, stderr = process.communicate()
                    
                    if process.returncode == 0 and os.path.exists(web_compatible_path) and os.path.getsize(web_compatible_path) > 0:
                        print(f"使用简化命令成功转换为H.264: {web_compatible_path}")
                        actual_output_path = web_compatible_path
                    else:
                        print(f"所有H.264转换尝试均失败，将使用原始视频")
            except Exception as e:
                print(f"转换视频格式时出错: {e}")
            
            # 将处理好的视频复制到静态资源目录，确保web服务器能访问
            try:
                static_dir = "data/static"
                os.makedirs(static_dir, exist_ok=True)
                static_filename = f"processed_{video_id}.mp4"
                static_path = os.path.join(static_dir, static_filename)
                
                # 复制文件到静态目录
                import shutil
                shutil.copy2(actual_output_path, static_path)
                
                print(f"已复制视频文件到静态资源目录: {static_path}")
                # 使用静态目录中的视频文件路径更新数据库
                actual_output_path = static_path
            except Exception as e:
                print(f"复制视频到静态目录时出错: {e}")
            
            # 检查 tracks 是否是有效的字典
            if not isinstance(tracks, dict):
                with open("data/temp_progress.txt", "w") as f:
                    f.write(f"error:{video_id}:返回的轨迹不是有效的字典，类型为 {type(tracks)}")
                return
            
            # 检查 tracks 是否为空
            if not tracks:
                print("没有跟踪到任何目标")
                # 仍然更新视频处理状态，标记为已处理但无轨迹数据
                db.update_video_processed(video_id, actual_output_path, duration)
                with open("data/temp_progress.txt", "w") as f:
                    f.write(f"complete:{video_id}")
                return
            
            # 保存轨迹数据到数据库
            trajectories_data = []
            for track_id, track_points in tracks.items():
                if not track_points:  # 跳过空轨迹
                    continue
                    
                for data_point in track_points:
                    try:
                        # 确保数据点是元组或列表且长度符合要求
                        if not isinstance(data_point, (tuple, list)) or len(data_point) < 5:
                            print(f"警告: 跳过无效的轨迹点数据: {data_point}")
                            continue
                            
                        frame, x, y, width, height = data_point
                        
                        # 构建轨迹数据
                        trajectories_data.append((
                            video_id, track_id, int(frame), 
                            float(x), float(y), float(width), float(height), 
                            1.0, None  # confidence 和 timestamp
                        ))
                    except Exception as e:
                        print(f"处理轨迹点数据时出错: {e}, 数据: {data_point}")
                        continue
            
            # 批量保存轨迹数据
            if trajectories_data:
                db.save_trajectories_batch(trajectories_data)
            else:
                print("警告: 没有有效的轨迹数据需要保存")
            
            # 更新视频处理状态 - 使用可能已修复并转换为Web兼容格式的视频路径
            db.update_video_processed(video_id, actual_output_path, duration)
            
            # 先设置进度为100%，确保UI会显示完成的进度
            with open("data/temp_progress_value.txt", "w") as f:
                f.write(f"{video_id}:100.0")
                
            # 将状态保存到临时文件，标记为完成
            with open("data/temp_progress.txt", "w") as f:
                f.write(f"complete:{video_id}")
                
        except Exception as e:
            print(f"处理视频时出错: {e}")
            with open("data/temp_progress.txt", "w") as f:
                f.write(f"error:{video_id if 'video_id' in locals() else '未知'}:{str(e)}")
                
    except Exception as e:
        print(f"处理视频出错: {e}")
        try:
            with open("data/temp_progress.txt", "w") as f:
                f.write(f"error:{video_id if 'video_id' in locals() else '未知'}:{str(e)}")
        except Exception as write_error:
            print(f"写入错误信息到文件时出错: {write_error}")
        print(f"处理视频时发生错误: {e}")

def process_video(video_id, video_path, output_path, conf_threshold):
    """在后台线程中处理视频 - 已弃用，使用process_video_safe代替"""
    try:
        # 获取视频信息
        cap = cv2.VideoCapture(video_path)
        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        fps = cap.get(cv2.CAP_PROP_FPS)
        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        duration = total_frames / fps if fps > 0 else 0
        cap.release()
        
        # 初始化检测器和跟踪器
        detector = PersonDetector(conf_thres=conf_threshold)
        tracker = PersonTracker(detector)
        
        # 跟踪视频
        tracks = tracker.track_video(video_path, output_path)
        
        # 保存轨迹数据到数据库
        trajectories_data = []
        for track_id, track_points in tracks.items():
            for frame, x, y, width, height in track_points:
                # 构建轨迹数据
                trajectories_data.append((
                    video_id, track_id, int(frame), 
                    float(x), float(y), float(width), float(height), 
                    1.0, None  # confidence 和 timestamp
                ))
        
        # 批量保存轨迹数据
        db.save_trajectories_batch(trajectories_data)
        
        # 更新视频处理状态
        db.update_video_processed(video_id, output_path, duration)
        
        # 更新进度为完成 - 不在线程中直接使用session_state
        # st.session_state.processing_videos[video_id]['progress'] = 100
        
    except Exception as e:
        # 记录错误 - 不在线程中直接使用session_state
        # st.session_state.processing_videos[video_id]['status'] = 'error'
        # st.session_state.processing_videos[video_id]['message'] = str(e)
        print(f"处理视频出错: {e}")

def update_progress(video_id, progress):
    """更新处理进度"""
    if video_id in st.session_state.processing_videos:
        st.session_state.processing_videos[video_id]['progress'] = progress

# 检查临时进度和错误文件
def check_process_status():
    """检查视频处理状态"""
    # 首先检查是否有实时进度更新
    if os.path.exists("data/temp_progress_value.txt"):
        try:
            with open("data/temp_progress_value.txt", "r") as f:
                content = f.read().strip()
                parts = content.split(":", 1)
                if len(parts) == 2:
                    video_id = int(parts[0])
                    progress = float(parts[1])
                    if video_id in st.session_state.processing_videos:
                        # 更新处理中的进度
                        current_status = st.session_state.processing_videos[video_id]['status']
                        current_progress = st.session_state.processing_videos[video_id]['progress']
                        
                        # 只有在处理中或进度值更高时才更新
                        if current_status == 'processing' and (progress > current_progress or progress == 100):
                            st.session_state.processing_videos[video_id]['progress'] = progress
                            print(f"更新视频 {video_id} 进度: {progress:.1f}%")
        except Exception as e:
            print(f"读取进度文件时出错: {e}")
    
    # 然后检查是否有完成标志
    if os.path.exists("data/temp_progress.txt"):
        try:
            with open("data/temp_progress.txt", "r") as f:
                content = f.read().strip()
                if content.startswith("complete:"):
                    video_id = int(content.split(":")[1])
                    if video_id in st.session_state.processing_videos:
                        # 标记处理已完成，并确保进度为100%
                        st.session_state.processing_videos[video_id]['progress'] = 100
                        st.session_state.processing_videos[video_id]['status'] = 'completed'
                        print(f"视频 {video_id} 处理完成")
                    # 删除完成标志文件
                    os.remove("data/temp_progress.txt")
        except Exception as e:
            print(f"读取完成标志文件时出错: {e}")
    
    # 最后检查是否有错误标志
    if os.path.exists("data/temp_error.txt"):
        try:
            with open("data/temp_error.txt", "r") as f:
                content = f.read().strip()
                if content.startswith("error:"):
                    parts = content.split(":", 2)
                    if len(parts) >= 3:
                        video_id = int(parts[1])
                        error_msg = parts[2]
                        if video_id in st.session_state.processing_videos:
                            st.session_state.processing_videos[video_id]['status'] = 'error'
                            st.session_state.processing_videos[video_id]['message'] = error_msg
                            print(f"视频 {video_id} 处理出错: {error_msg}")
                    # 删除错误标志文件
                    os.remove("data/temp_error.txt")
        except Exception as e:
            print(f"读取错误标志文件时出错: {e}")

def get_video_serving_path(file_path):
    """
    获取适合Streamlit服务的视频路径
    
    参数:
        file_path: 原始视频文件路径
    
    返回:
        serving_path: 可以被Streamlit服务的路径
    """
    # 检查文件是否存在
    if not os.path.exists(file_path):
        print(f"文件不存在: {file_path}")
        return None
    
    # 如果路径已经在静态目录中，直接返回
    if "data/static" in file_path:
        return file_path
    
    # 否则，复制到静态目录
    try:
        static_dir = "data/static"
        os.makedirs(static_dir, exist_ok=True)
        
        # 生成唯一文件名，避免缓存问题
        filename = os.path.basename(file_path)
        name, ext = os.path.splitext(filename)
        timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
        static_filename = f"{name}_{timestamp}{ext}"
        static_path = os.path.join(static_dir, static_filename)
        
        # 复制文件
        import shutil
        shutil.copy2(file_path, static_path)
        print(f"已复制视频到静态目录: {static_path}")
        
        return static_path
    except Exception as e:
        print(f"复制视频到静态目录时出错: {e}")
        return file_path

def serve_video(video_path):
    """
    使用Streamlit视频组件播放视频
    
    参数:
        video_path: 视频文件路径
    """
    if not os.path.exists(video_path):
        st.error(f"视频文件不存在: {video_path}")
        return False
    
    # 添加视频格式检查
    try:
        import subprocess
        # 使用FFprobe检查视频编码
        cmd = ['ffprobe', '-v', 'error', '-select_streams', 'v:0', 
               '-show_entries', 'stream=codec_name', '-of', 'default=noprint_wrappers=1:nokey=1', 
               video_path]
        
        try:
            result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            codec = result.stdout.strip()
            st.info(f"视频编码: {codec}")
            
            # 如果不是H.264，显示警告
            if codec and codec.lower() not in ['h264', 'avc1', 'x264']:
                st.warning(f"视频不是使用H.264编码，可能影响播放兼容性。当前编码: {codec}")
        except Exception as e:
            st.warning(f"无法检测视频编码: {e}")
    except Exception:
        # FFprobe可能不可用
        pass
    
    # 准备视频路径
    serving_path = get_video_serving_path(video_path)
    if not serving_path:
        st.error("无法获取可服务的视频路径")
        return False
    
    # 使用Streamlit视频组件播放视频
    try:
        st.write("### 视频播放")
        st.video(serving_path)
        st.success("视频加载成功！")
        success = True
    except Exception as e:
        st.error(f"视频播放失败: {str(e)}")
        success = False
    
    # 显示视频文件详细信息
    with st.expander("视频文件详细信息"):
        st.write(f"文件路径: {serving_path}")
        st.write(f"文件大小: {os.path.getsize(serving_path) / (1024*1024):.2f} MB")
        st.write(f"文件修改时间: {datetime.fromtimestamp(os.path.getmtime(serving_path))}")
        
        # 尝试获取更多视频信息
        try:
            cap = cv2.VideoCapture(serving_path)
            if cap.isOpened():
                width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
                height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
                fps = cap.get(cv2.CAP_PROP_FPS)
                frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
                duration = frame_count / fps if fps > 0 else 0
                
                st.write(f"分辨率: {width}x{height}")
                st.write(f"帧率: {fps} FPS")
                st.write(f"帧数: {frame_count}")
                st.write(f"时长: {duration:.2f} 秒")
                
                # 读取第一帧并显示缩略图
                ret, frame = cap.read()
                if ret:
                    st.write("视频缩略图预览:")
                    # 缩小图像以适合显示
                    scale = 400 / max(width, height)
                    thumbnail = cv2.resize(frame, (int(width * scale), int(height * scale)))
                    st.image(thumbnail, channels="BGR")
                
                cap.release()
            else:
                st.error("无法使用OpenCV打开视频文件")
        except Exception as e:
            st.error(f"获取视频详情出错: {str(e)}")
    
    return success 